package com.andova.view;

import android.animation.Animator;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.AutoCompleteTextView;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.FloatRange;
import androidx.annotation.Keep;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.view.ViewCompat;

import com.andova.common.R;

/**
 * Created by Administrator on 2018-05-07.
 *
 * @author kzaxil
 * @since 1.0.0
 */
@Keep
public class SearchView extends ConstraintLayout implements TextWatcher,
        TextView.OnEditorActionListener, ValueAnimator.AnimatorUpdateListener {
    private String mText;
    /**
     * 搜索框是否折叠
     */
    private boolean mCollapsed = false;
    private ValueAnimator mAnimator;
    private AnimatorElement mEndElement;
    private AnimatorElement mStartElement;
    private AnimatorEvaluator mEvaluator = new AnimatorEvaluator();

    private View vRoot;
    private ImageView ivClose;
    private ImageView ivSearch;
    private View searchContent;
    private AutoCompleteTextView etText;

    public SearchView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SearchView);
        vRoot = LayoutInflater.from(context).inflate(R.layout.andova_view_search, this, true);
        ivClose = findViewById(R.id.iv_close_icon);
        ivClose.setPadding(
                ta.getDimensionPixelOffset(R.styleable.SearchView_clearIconPadding, 0),
                ta.getDimensionPixelOffset(R.styleable.SearchView_clearIconPadding, 0),
                ta.getDimensionPixelOffset(R.styleable.SearchView_clearIconPadding, 0),
                ta.getDimensionPixelOffset(R.styleable.SearchView_clearIconPadding, 0));
        searchContent = findViewById(R.id.searchContent);
        ViewCompat.setBackground(searchContent, ta.getDrawable(R.styleable.SearchView_searchViewBackground));
        ivSearch = findViewById(R.id.iv_search_icon);
        etText = findViewById(R.id.et_search_text);
        float textSize = ta.getDimensionPixelOffset(R.styleable.SearchView_searchViewTextSize, 0);
        if (textSize > 0) {
            etText.setTextSize(textSize);
        }
        if (ta.getColor(R.styleable.SearchView_searchViewTextColor, 0) != 0) {
            etText.setTextColor(ta.getColor(R.styleable.SearchView_searchViewTextColor, 0));
        }
        ConstraintLayout.LayoutParams lp = (LayoutParams) etText.getLayoutParams();
        lp.setMargins(ta.getDimensionPixelOffset(R.styleable.SearchView_searchViewPaddingLeft, 0),
                ta.getDimensionPixelOffset(R.styleable.SearchView_searchViewPaddingTop, 0),
                ta.getDimensionPixelOffset(R.styleable.SearchView_searchViewPaddingRight, 0),
                ta.getDimensionPixelOffset(R.styleable.SearchView_searchViewPaddingBottom, 0));
        etText.addTextChangedListener(this);
        etText.setOnEditorActionListener(this);
        etText.setSingleLine(true);
        ivClose.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                etText.getText().clear();
            }
        });
        ta.recycle();
    }

    private void initAnimator(boolean shouldAddListener) {
        mAnimator = null;
        if (mStartElement == null) {
            mStartElement = new AnimatorElement();
            mStartElement.rootWidth = vRoot.getWidth();
            mStartElement.rootHeight = vRoot.getHeight();
            mStartElement.searchWidth = searchContent.getWidth();
            mStartElement.searchPaddingLeft = searchContent.getPaddingLeft();
            mStartElement.searchPaddingTop = searchContent.getPaddingTop();
            mStartElement.searchPaddingRight = searchContent.getPaddingRight();
            mStartElement.searchPaddingBottom = searchContent.getPaddingBottom();
            mStartElement.padding = getPaddingTop();
        }
        if (mEndElement == null) {
            mEndElement = new AnimatorElement();
            mEndElement.rootWidth = ivSearch.getWidth();
            mEndElement.rootHeight = ivSearch.getHeight();
            mEndElement.searchWidth = 0;
            mEndElement.searchPaddingLeft = 0;
            mEndElement.searchPaddingTop = 0;
            mEndElement.searchPaddingRight = 0;
            mEndElement.searchPaddingBottom = 0;
            mEndElement.padding = 0;
        }
        mAnimator = ValueAnimator.ofObject(mEvaluator, mCollapsed ? mEndElement : mStartElement, mCollapsed ? mStartElement : mEndElement);
        if (!shouldAddListener) return;
        mAnimator.addUpdateListener(this);
        mAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
                if (searchContent.getVisibility() == GONE) searchContent.setVisibility(VISIBLE);
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                if (mCollapsed && searchContent.getVisibility() == VISIBLE)
                    searchContent.setVisibility(GONE);
            }

            @Override
            public void onAnimationCancel(Animator animation) {
            }

            @Override
            public void onAnimationRepeat(Animator animation) {
            }
        });
        mAnimator.setDuration(500L);
    }

    private void animationUpdate(AnimatorElement element) {
        int padding = element.padding;
        vRoot.getLayoutParams().width = element.rootWidth;
        vRoot.getLayoutParams().height = element.rootHeight;
        searchContent.getLayoutParams().width = element.searchWidth;
        searchContent.setPadding(
                element.searchPaddingLeft,
                element.searchPaddingTop,
                element.searchPaddingRight,
                element.searchPaddingBottom
        );
        vRoot.setPadding(padding, padding, padding, padding);
    }

    public void collapse() {
        if (mCollapsed) return;
        initAnimator(true);
        mText = etText.getText().toString();
        etText.getText().clear();
        mAnimator.start();
        mCollapsed = true;
    }

    public void collapse(@FloatRange(from = 0, to = 1) float percent) {
        if (mCollapsed) return;
        initAnimator(false);
        mText = etText.getText().toString();
        etText.getText().clear();
        AnimatorElement element = mEvaluator.evaluate(percent, mCollapsed ? mEndElement : mStartElement, mCollapsed ? mStartElement : mEndElement);
        animationUpdate(element);
        if (percent >= 1f) {
            if (searchContent.getVisibility() == VISIBLE) searchContent.setVisibility(GONE);
        } else {
            if (searchContent.getVisibility() == GONE) searchContent.setVisibility(VISIBLE);
        }
    }

    public void expand() {
        if (!mCollapsed) return;
        initAnimator(true);
        etText.setText(mText);
        mAnimator.start();
        mCollapsed = false;
    }

    public String getText() {
        return etText.getText().toString();
    }

    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        AnimatorElement element = (AnimatorElement) animation.getAnimatedValue();
        animationUpdate(element);
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {

    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {

    }

    @Override
    public void afterTextChanged(Editable s) {
        if (TextUtils.isEmpty(s.toString())) {
            if (ivClose.getVisibility() != GONE) ivClose.setVisibility(GONE);
        } else {
            if (ivClose.getVisibility() != VISIBLE) ivClose.setVisibility(VISIBLE);
        }
    }

    @Override
    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
        if (actionId == EditorInfo.IME_ACTION_SEARCH) {
            // 当按了搜索之后关闭软键盘
            hideKeyboard();
            if (mSearchListener != null) mSearchListener.search(etText.getText().toString());
            return true;
        }
        return false;
    }

    private void hideKeyboard() {
        InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        if (imm == null || !imm.isActive()) return;
        if (getWindowToken() != null) {
            imm.hideSoftInputFromWindow(getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
        }
    }

    private OnSearchListener mSearchListener;

    public interface OnSearchListener {
        void search(String s);
    }

    public void setOnSearchListener(OnSearchListener listener) {
        mSearchListener = listener;
    }

    private class AnimatorElement {
        int padding;
        int rootWidth;
        int rootHeight;
        int searchWidth;
        int searchPaddingLeft;
        int searchPaddingTop;
        int searchPaddingRight;
        int searchPaddingBottom;
    }

    private int value(float fraction, int startValue, int endValue) {
        return (int) (startValue - fraction * (startValue - endValue));
    }

    private class AnimatorEvaluator implements TypeEvaluator<AnimatorElement> {
        @Override
        public AnimatorElement evaluate(float fraction, AnimatorElement startValue, AnimatorElement endValue) {
            AnimatorElement element = new AnimatorElement();
            element.padding = value(fraction, startValue.padding, endValue.padding);
            element.rootWidth = value(fraction, startValue.rootWidth, endValue.rootWidth);
            element.rootHeight = value(fraction, startValue.rootHeight, endValue.rootHeight);
            element.searchWidth = value(fraction, startValue.searchWidth, endValue.searchWidth);
            element.searchPaddingLeft = value(fraction, startValue.searchPaddingLeft, endValue.searchPaddingLeft);
            element.searchPaddingTop = value(fraction, startValue.searchPaddingTop, endValue.searchPaddingTop);
            element.searchPaddingRight = value(fraction, startValue.searchPaddingRight, endValue.searchPaddingRight);
            element.searchPaddingBottom = value(fraction, startValue.searchPaddingBottom, endValue.searchPaddingBottom);
            return element;
        }
    }
}
